package com.zhang.quartz;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zhang.entity.JobDetails;
import com.zhang.entity.QuartzBody;
import com.zhang.exception.ServiceException;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * User: 张
 * Date: 2024-11-28
 * Time: 10:13
 * Description:
 */
@Component
public class QuartzManager {
    @Autowired
    private Scheduler scheduler;

    /**
     * 通过判断定时任是否存在，添加或修改定时任务
     *
     * @param quartzBody Class<? extends QuartzJobBean> jobClass
     *                   String jobName;
     *                   String jobGroupName;
     *                   String jobCron;
     *                   JobDataMap jobDataMap;
     */
    public void addOrUpdateJob(QuartzBody quartzBody) {
        try {
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(TriggerKey.triggerKey(quartzBody.getJobName(), quartzBody.getJobGroupName()));
            if (trigger == null) addJob(quartzBody);
            else if (!trigger.getCronExpression().equals(quartzBody.getJobCron())) updateJob(quartzBody);
        } catch (SchedulerException e) {
            throw new ServiceException("定时任务获取失败");
        }
    }

    /**
     * 添加定时任务
     *
     * @param quartzBody Class<? extends QuartzJobBean> jobClass
     *                   String jobName;
     *                   String jobGroupName;
     *                   String jobCron;
     *                   JobDataMap jobDataMap;
     */
    private void addJob(QuartzBody quartzBody) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(quartzBody.getJobClass())
                    .usingJobData(quartzBody.getJobDataMap())
                    .withIdentity(quartzBody.getJobName(), quartzBody.getJobGroupName())
                    .build();
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(quartzBody.getJobName(), quartzBody.getJobGroupName())
                    .startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.SECOND))
                    .withSchedule(CronScheduleBuilder.cronSchedule(quartzBody.getJobCron()))
                    .startNow()
                    .build();
            scheduler.scheduleJob(jobDetail, trigger);
            if (!scheduler.isShutdown()) scheduler.start();
        } catch (SchedulerException e) {
            throw new ServiceException("添加定时任务失败");
        }
    }

    /**
     * 修改定时任务
     *
     * @param quartzBody String jobName;
     *                   String jobGroupName;
     *                   String jobCron;
     */
    private void updateJob(QuartzBody quartzBody) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(quartzBody.getJobGroupName(), quartzBody.getJobGroupName());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            trigger = trigger.getTriggerBuilder()
                    .withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(quartzBody.getJobCron()))
                    .build();
            // 重启触发器
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            throw new ServiceException("更新定时任务失败");
        }
    }

    /**
     * 删除定时任务
     *
     * @param quartzBody String jobName;
     *                   String jobGroupName;
     */
    public void deleteJob(QuartzBody quartzBody) {
        try {
            scheduler.pauseTrigger(TriggerKey.triggerKey(quartzBody.getJobGroupName(), quartzBody.getJobGroupName()));
            scheduler.unscheduleJob(TriggerKey.triggerKey(quartzBody.getJobGroupName(), quartzBody.getJobGroupName()));
            scheduler.deleteJob(new JobKey(quartzBody.getJobGroupName(), quartzBody.getJobGroupName()));
        } catch (SchedulerException e) {
            throw new ServiceException("删除定时任务失败");
        }
    }

    /**
     * 暂停一个job
     *
     * @param quartzBody String jobName;
     *                   String jobGroupName;
     */
    public void pauseJob(QuartzBody quartzBody) {
        try {
            scheduler.pauseJob(JobKey.jobKey(quartzBody.getJobGroupName(), quartzBody.getJobGroupName()));
        } catch (SchedulerException e) {
            throw new ServiceException("暂停定时任务异常");
        }
    }

    /**
     * 恢复定时任务
     *
     * @param quartzBody String jobName;
     *                   String jobGroupName;
     */
    public void resumeJob(QuartzBody quartzBody) {
        try {
            scheduler.resumeJob(JobKey.jobKey(quartzBody.getJobGroupName(), quartzBody.getJobGroupName()));
        } catch (SchedulerException e) {
            throw new ServiceException("恢复定时任务异常");
        }
    }

    /**
     * 立即执行定时任务
     *
     * @param quartzBody String jobName;
     *                   String jobGroupName;
     */
    public void runAJobNow(QuartzBody quartzBody) {
        try {
            scheduler.triggerJob(JobKey.jobKey(quartzBody.getJobGroupName(), quartzBody.getJobGroupName()));
        } catch (SchedulerException e) {
            throw new ServiceException("立即执行定时任务异常");
        }
    }

    /**
     * 分页查询所有任务
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    public PageInfo<JobDetails> queryAllJobBean(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<JobDetails> jobList = null;
        try {
            GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
            Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
            jobList = new ArrayList<>();
            for (JobKey jobKey : jobKeys) {
                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                for (Trigger trigger : triggers) {
                    JobDetails jobDetails = new JobDetails();
                    if (trigger instanceof CronTrigger) {
                        CronTrigger cronTrigger = (CronTrigger) trigger;
                        jobDetails.setCronExpression(cronTrigger.getCronExpression());
                        jobDetails.setTimeZone(cronTrigger.getTimeZone().getDisplayName());
                    }
                    jobDetails.setTriggerGroupName(trigger.getKey().getName())
                            .setTriggerName(trigger.getKey().getGroup())
                            .setJobGroupName(jobKey.getGroup())
                            .setJobName(jobKey.getName())
                            .setStartTime(trigger.getStartTime())
                            .setJobClassName(scheduler.getJobDetail(jobKey).getJobClass().getName())
                            .setNextFireTime(trigger.getNextFireTime())
                            .setPreviousFireTime(trigger.getPreviousFireTime())
                            .setStatus(scheduler.getTriggerState(trigger.getKey()).name())
                            .setJobDataMap(scheduler.getJobDetail(jobKey).getJobDataMap());
                    jobList.add(jobDetails);
                }
            }
        } catch (SchedulerException e) {
            throw new ServiceException("查询全部定时任务异常");
        }
        return new PageInfo<>(jobList);
    }

    /**
     * 分页查询所有正在运行的任务
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    public PageInfo<JobDetails> queryRunJon(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<JobDetails> jobList = null;
        try {
            List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
            jobList = new ArrayList<>(executingJobs.size());
            for (JobExecutionContext executingJob : executingJobs) {
                JobDetails jobDetails = new JobDetails();
                JobDetail jobDetail = executingJob.getJobDetail();
                JobKey jobKey = jobDetail.getKey();
                Trigger trigger = executingJob.getTrigger();
                jobDetails.setJobName(jobKey.getName())
                        .setJobGroupName(jobKey.getGroup())
                        .setJobClassName(jobDetail.getJobClass().getName())
                        .setTriggerName(trigger.getKey().getName())
                        .setTriggerGroupName(trigger.getKey().getGroup())
                        .setStartTime(trigger.getStartTime())
                        .setNextFireTime(trigger.getNextFireTime())
                        .setPreviousFireTime(trigger.getPreviousFireTime())
                        .setStatus(scheduler.getTriggerState(trigger.getKey()).name())
                        .setJobDataMap(jobDetail.getJobDataMap());
                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    jobDetails.setCronExpression(cronExpression);
                }
                jobList.add(jobDetails);
            }
        } catch (SchedulerException e) {
            throw new ServiceException("查询正在运行定时任务异常");
        }
        return new PageInfo<>(jobList);
    }

}
